#ifndef __WIZ_BNF_GRAMMAR_HPP__SHANHAOBO_19800429__
#define __WIZ_BNF_GRAMMAR_HPP__SHANHAOBO_19800429__

#include <algorithm>
#include <functional>

#include "../../System/Thread/WizThreadTLS.hpp"
#include "../../System/WizStatic.hpp"

#include "../WizBNFContext.hpp"

#include "./WizBNFObjectWithID.hpp"
#include "./WizBNFGrammarHelper.hpp"

namespace Wiz
{
    namespace BNF
    {
        namespace Grammar
        {
            namespace Tag
            {
                struct Type
                {};
            } /// end of namespace Tag
            ///////////////////////////////////////////////////////////////////////////
            //
            //  EntryGrammar class
            //
            ///////////////////////////////////////////////////////////////////////////
            template <typename DerivedT, ::Wiz::Int::Type N, typename ContextT>
            class EntryGrammar : public ::Wiz::BNF::Parser::Type<EntryGrammar<DerivedT, N, ContextT>>
            {

            public:
                typedef EntryGrammar<DerivedT, N, ContextT>     tThis;
                typedef tThis                                   tEmbedded;
                typedef typename ContextT::tContextLinker       tContextLinker;
                typedef typename tContextLinker::tAttribute     tAttribute;

                template <typename ScannerT>
                struct Result
                {
                    typedef typename ::Wiz::BNF::Match::Result<ScannerT, tAttribute>::tType tType;
                };

                EntryGrammar(DerivedT const &Prs) : m_TargetGrammar(Prs) {}

                template <typename ScannerT>
                typename ::Wiz::BNF::Parser::Result<tThis, ScannerT>::tType
                ParseMain(ScannerT const& Scan) const
                {
                    return ::Wiz::BNF::Grammar::GrammarParserParse<N>(&m_TargetGrammar, Scan);
                }

                template <typename ScannerT>
                typename ::Wiz::BNF::Parser::Result<tThis, ScannerT>::tType
                ParseImpl(ScannerT const& Scan) const
                {
                    typedef ::Wiz::BNF::Scanner::Linker::Type<ScannerT>                 tScannerLinker;
                    typedef typename ::Wiz::BNF::Parser::Result<tThis, ScannerT>::tType tResult;

                    tScannerLinker ScanWrap(Scan);
                    tContextLinker ContextWrap(m_TargetGrammar); 
                    ContextWrap.PreParse(m_TargetGrammar, ScanWrap);
                    tResult Hit = ParseMain(Scan);
                    return ContextWrap.PostParse(Hit, m_TargetGrammar, ScanWrap);
                }
            private:
                DerivedT const &m_TargetGrammar;
            };

            ///////////////////////////////////////////////////////////////////////////////
            //
            //  Type class
            //
            ///////////////////////////////////////////////////////////////////////////////
            template <typename DerivedT, typename ContextT = ::Wiz::BNF::Context::Type<>>
            struct Type :
                public ::Wiz::BNF::Parser::Type<DerivedT>,
                public ContextT::tSuper,
                public ::Wiz::BNF::Context::AUX::Type<ContextT, DerivedT>,
                public ::Wiz::BNF::ObjectWithID::Type<::Wiz::BNF::Grammar::Tag::Type>
            {
                typedef Type<DerivedT, ContextT>            tThis;
                typedef DerivedT const&                     tEmbedded;
                typedef typename ContextT::tContextLinker   tContextLinker;
                typedef typename ContextT::tAttribute       tAttribute;

                template <typename ScannerT>
                struct Result
                {
                    typedef typename ::Wiz::BNF::Match::Result<ScannerT, tAttribute>::tType tType;
                };

                Type()
                {}
                ~Type()
                {
                    ::Wiz::BNF::Grammar::GrammarDestruct(this);
                }

                template <typename ScannerT>
                typename ::Wiz::BNF::Parser::Result<tThis, ScannerT>::tType
                ParseMain(ScannerT const& Scan) const
                {
                    return ::Wiz::BNF::Grammar::GrammarParserParse<0>(this, Scan);
                }

                template <typename ScannerT>
                typename ::Wiz::BNF::Parser::Result<tThis, ScannerT>::tType
                Parse(ScannerT const& Scan) const
                {
                    typedef typename ::Wiz::BNF::Parser::Result<tThis, ScannerT>::tType tResult;
                    typedef ::Wiz::BNF::Scanner::Linker::Type<ScannerT>                 tScannerLinker;

                    tScannerLinker ScanWrap(Scan);
                    tContextLinker ContextWrap(*this); 
                    ContextWrap.PreParse(*this, ScanWrap);
                    tResult Hit = ParseMain(Scan);
                    return ContextWrap.PostParse(Hit, *this, ScanWrap);
                }

                template <::Wiz::Int::Type N>
                EntryGrammar<DerivedT, N, ContextT>
                UseParser() const
                {
                    return EntryGrammar<DerivedT, N, ContextT>( this->Derived());
                }

                mutable ::Wiz::BNF::Grammar::Helper::List::Type<tThis> m_Helpers;
            };

            //////////////////////////////////////////////////////////////////////////
            template <::Wiz::Int::Type N>
            struct CallHelper
            {

                template <typename RT, typename DefinitionT, typename ScannerT>
                static ::Wiz::Void::Type
                Do(RT &Rslt, DefinitionT &Def, ScannerT const &Scan)
                {
                    Rslt = Def.template GetStartParser<N>()->Parse(Scan);
                }
            };

            template <>
            struct CallHelper<0>
            {
                template <typename RT, typename DefinitionT, typename ScannerT>
                static ::Wiz::Void::Type
                Do(RT &Rslt, DefinitionT &Def, ScannerT const &Scan)
                {
                    Rslt = Def.Start().Parse(Scan);
                }
            };

            //////////////////////////////////
            template<::Wiz::Int::Type N, typename DerivedT, typename ContextT, typename ScannerT>
            WIZ_INLINE typename ::Wiz::BNF::Parser::Result<::Wiz::BNF::Grammar::Type<DerivedT, ContextT>, ScannerT>::tType
            GrammarParserParse
            (
                ::Wiz::BNF::Grammar::Type<DerivedT, ContextT> const*  Self,
                ScannerT const &Scan
            )
            {
                typedef
                    typename ::Wiz::BNF::Parser::Result<::Wiz::BNF::Grammar::Type<DerivedT, ContextT>, ScannerT>::tType
                    tResult;
                typedef typename DerivedT::template Definition<ScannerT> tDefinition;

                tResult Rslt;
                tDefinition &Def = GetDefinition<DerivedT, ContextT, ScannerT>(Self);

                CallHelper<N>::Do(Rslt, Def, Scan);
                return Rslt;
            }

            //////////////////////////////////////////////////////////////////////////

            template<typename GrammarT>
            inline ::Wiz::Void::Type GrammarDestruct(GrammarT* Self)
            {
                typedef ::Wiz::BNF::Grammar::Helper::Base::Type<GrammarT>   tHelperBase;
                typedef ::Wiz::BNF::Grammar::Helper::List::Type<GrammarT>   tHelperList;
                typedef typename tHelperList::tArray::tReverseIterator      tIterator;

                tHelperList&  helpers = Self->m_Helpers;
                tIterator i;

                for (i = helpers.RBegin(); i != helpers.REnd(); ++i)
                {
                    (*i)->Undefine(Self);
                }
            }

            template<typename DerivedT, typename ContextT, typename ScannerT>
            WIZ_INLINE typename DerivedT::template Definition<ScannerT> &
            GetDefinition(::Wiz::BNF::Grammar::Type<DerivedT, ContextT> const*  Self)
            {
                struct tGetDefinitionStaticDataTag
                {
                    tGetDefinitionStaticDataTag()
                    {}
                };

                typedef ::Wiz::BNF::Grammar::Type<DerivedT, ContextT>                       tGrammar;
                typedef ::Wiz::BNF::Grammar::Helper::Type<tGrammar, DerivedT, ScannerT>     tHelper;
                typedef typename tHelper::tThisWeakPtr                                      tWeakPtr;

                static ::Wiz::Thread::TLS::Type<tWeakPtr>& TLSHlpr
                    = ::Wiz::Static::Type<::Wiz::Thread::TLS::Type<tWeakPtr>, tGetDefinitionStaticDataTag>(tGetDefinitionStaticDataTag());

                if (TLSHlpr.NotValid())
                {
                    TLSHlpr.Reset(new tWeakPtr);
                }
                tWeakPtr &Hlpr = *TLSHlpr;

                if (Hlpr.Expired())
                {
                    new tHelper(Hlpr);
                }
                return Hlpr.Lock()->Define(Self);
            }
        } /// end of namespace Grammar
    } /// end of namespace BNF
} /// end of namespace Wiz

#endif /*__WIZ_BNF_GRAMMAR_HPP__SHANHAOBO_19800429__*/
